#!/usr/bin/env ruby

require 'net/http'
require 'optparse'
require 'cgi'

$CFG = {
  :host => 'localhost',
  :port => 3000,
  :user => '',
  :pass => '',
  :method => 'GET',
  :data => {}
}

# data for the POST and PUT methods
# in format 'param1[val1]=xxx;param2[val2]=yyy'
# delimiter can be ';', ',' or ':'
def parse_data(data)
  res = Hash.new([])
  return res unless data

  data.split(/[;,:]\s?/).each do |pairs|
    name, value = pairs.split('=',2)
    next unless name and value
    res.merge!({ name.strip => value.strip })
  end
  res
end 

opts = OptionParser.new do |opts|
  opts.banner = "Usage: rest_client [options ...] command"
  opts.define_head "Pure Ruby client for testing REST services"
  opts.separator ""
  opts.separator "Options:"

  opts.on("-h", "--host HOSTNAME", "Host to bind to (default is 'localhost')") do |v|
    $CFG[:host] = v
  end
  opts.on("-P", "--port NUM", "Port (default is 3000)") do |v|
    $CFG[:port] = v.to_i
  end
  opts.on("-u", "--user USER", "Username for authentication") do |v|
    $CFG[:user] = v
  end
  opts.on("-p", "--pass PASSWORD", "Password for authentication") do |v|
    $CFG[:pass] = v
  end
  opts.on("-X", "--method METHOD", "HTTP method to use (default is 'GET')") do |v|
    $CFG[:method] = v
  end
  opts.on("-d", "--data DATA", "Request ('POST' and 'PUT' only) additional data") do |v|
    $CFG[:data] = parse_data(v)
  end

  # No argument, shows at tail.  This will print an options summary.
  opts.on_tail("-?", "--help", "Show this message") do
    puts opts
    exit
  end
end

opts.parse! ARGV
if ARGV.length < 1
  puts opts
  exit
end

cmd = ARGV.shift

def http_method(method)
  case method
    when 'GET'
      return Net::HTTP::Get
    when 'POST'
      return Net::HTTP::Post
    when 'PUT'
      return Net::HTTP::Put
    when 'DELETE'
      return Net::HTTP::Delete
    else
      raise "Unsupported method #{method}"
  end
end

Net::HTTP.start($CFG[:host], $CFG[:port]) do |http|

  req = http_method($CFG[:method]).new("#{cmd}")
  req['Accept'] = 'application/xml'
  unless ($CFG[:user] == '' || $CFG[:pass] == '')
    req.basic_auth($CFG[:user],$CFG[:pass]);
  end

  # TODO: how to input form data from the command line?
  if ($CFG[:method] == 'POST' || $CFG[:method] == 'PUT')
    req.set_form_data($CFG[:data])
  end 

    
  response = http.request(req)


  #Do something with the response.

  puts "Code: #{response.code}" 
  puts "Message: #{response.message}"
  puts "Body:\n #{response.body}"
end
